package com.zhuhao.basic.completablefuture;

import com.zhuhao.basic.completablefuture.tuils.ThreadPoolConfig;
import org.junit.Before;
import org.junit.Test;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;

/**
 * 教程：https://zhuanlan.zhihu.com/p/344431341
 * 在Java 8中, 新增加了一个包含50个方法左右的类: CompletableFuture，结合了Future的优点，提供了非常强大的Future的扩展功能，
 * 可以帮助我们简化异步编程的复杂性，提供了函数式编程的能力，可以通过回调的方式处理计算结果，并且提供了转换和组合CompletableFuture
 * 的方法。
 * CompletableFuture被设计在Java中进行异步编程。异步编程意味着在主线程之外创建一个独立的线程，与主线程分隔开，并在上面运行一个
 * 非阻塞的任务，然后通知主线程进展，成功或者失败。
 * <p>
 * public static <U> CompletableFuture<U> supplyAsync(Supplier<U> supplier);
 * public static <U> CompletableFuture<U> supplyAsync(Supplier<U> supplier, Executor executor);
 * public static CompletableFuture<Void> runAsync(Runnable runnable);
 * public static CompletableFuture<Void> runAsync(Runnable runnable, Executor executor);
 * <p>
 * 有两种格式，一种是supply开头的方法，一种是run开头的方法
 * <p>
 * supply开头：这种方法，可以返回异步线程执行之后的结果
 * run开头：这种不会返回结果，就只是执行线程任务
 *
 * @Author zhuhao
 * @Date 2022/4/15 16:05
 * @desc
 */
public class CompletableFutureDemo01 {

    ExecutorService executorService = null;

    @Before
    public void before() {
        executorService = ThreadPoolConfig.executorService();
    }

    @Test
    public void test01() throws ExecutionException, InterruptedException {
        CompletableFuture<Object> future = new CompletableFuture<>();
        //get() 方法同样会阻塞直到任务完成
        future.get();
    }

    /**
     * 计算完成后续操作
     */
    @Test
    public void test02() {
        CompletableFuture<Integer> future = CompletableFuture.supplyAsync(() -> {
            int i = 7 / 0;
            return 111;
        }, executorService);

        //同步
        future.whenComplete((result, error) -> {
            System.out.println(result);
            System.out.println(error.getMessage());
        });
        //异步
        future.whenCompleteAsync((result, error) -> {
            System.out.println(result);
        });
    }

    /**
     * 计算完成后续操作2
     */
    @Test
    public void test03() {
        CompletableFuture<List<String>> future = CompletableFuture.supplyAsync(() -> {
            List<String> list = new ArrayList<>();
            list.add("语文");
            list.add("数学");
            // 获取得到今天的所有课程
            return list;
        }, executorService);

        //不用返回新结果，需要处理异常
        future.whenCompleteAsync((result, error) -> {
            for (String s : result) {
                System.out.print(s);
            }
            result.remove(0);
            System.out.println();
        }, executorService).whenCompleteAsync((result, error) -> {
            for (String s : result) {
                System.out.print(s);
            }
            System.out.println();
        }, executorService);

        //apply需要返回一个新的结果用于链式调用，且不用处理异常，异常上抛
        CompletableFuture<List<String>> future2 = future.thenApplyAsync((result) -> {
            for (String s : result) {
                System.out.print(s);
            }
            System.out.println();
            return result;
        });

        //只做最终结果的消费，注意此时返回的CompletableFuture是空返回。只消费，无返回，有点像流式编程的终端操作。
        future2.thenAcceptAsync((result) -> {
            for (String s : result) {
                System.out.print(s);
            }
        });
    }

    /**
     * 捕获中间产生的异常
     */
    @Test
    public void test04() {
        // 实例化一个CompletableFuture,返回值是Integer
        CompletableFuture<Integer> future = CompletableFuture.supplyAsync(() -> {
            // 返回null
            return 1;
        });

        future.thenApply(result -> {
            System.out.println(result);
            // 制造一个空指针异常NPE
            int i = 1 / 0;
            return i;
        }).thenApply(result -> {
            System.out.println("ddd" + result);
            return "eeee";
        }).exceptionally(error -> {
            System.out.println(error.getMessage());
            return "出错啊~";
        }).thenAccept(System.out::println);
    }

    @Test
    public void test05() throws ExecutionException, InterruptedException {

        List<CompletableFuture<List<Integer>>> futureList = new ArrayList<>();
        for (int i = 0; i < 10; i++) {
            int finalI = i;
            CompletableFuture<List<Integer>> listCompletableFuture = CompletableFuture.supplyAsync(() -> {
                try {
                    Thread.sleep(finalI * 100);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                return Arrays.asList(finalI);
            });
            futureList.add(listCompletableFuture);
        }

        CompletableFuture.allOf(futureList.toArray(new CompletableFuture[]{})).get();

        ArrayList<Integer> allList = new ArrayList<>();
        for (CompletableFuture<List<Integer>> listCompletableFuture : futureList) {
            List<Integer> join = listCompletableFuture.join();
            allList.addAll(join);
        }

        allList.forEach(System.out::println);

    }

}
